(function(){
	'use strict';
	/**
	 * zhx calendar base on Angular
	 *
	 * Author : Vicco Wang
	 * Date : 2016.10.11
	 * 
	 * Deps:
	 * [jQuery]
	 * [Angular]
	 * [Moment]
	 * 
	 */
	var CALENDAR = angular.module('zhxBaseCalendar',[]);

	CALENDAR.provider("zhxBaseCalendar", function(){

		var config = {
			locale 	: 'zh-cn',
			showHoliday : false,
			holidayUrl : null
		};

		this.config = function(cfg){
			//angular.merge support deep copy!
			config = angular.merge({}, config, cfg);
			//设置moment为简体中文环境
			moment.locale( config.locale );
		};

		this.$get = function(){
			return {
				isLocale : function(){
					return config.locale === 'zh-cn';
				},
				showHoliday : function(){
					return config. showHoliday;
				},
				getHolidayUrl : function(){
					return config.holidayUrl;
				}
			}
		};

	});

	/**
	 * 日历工具集
	 */
	CALENDAR.factory('zhxBaseCalUtils',['zhxBaseCalendar','$http','$q','$compile','$timeout',function(zhxBaseCalendar,$http,$q,$compile,$timeout){

		var service = {},
			holiday = null,
			isShowLoading = false,showLoadingTimeout,
			calStartDate,calEndDate,
			eventStartDate,eventEndDate,
			holidayDefer = $q.defer();

		//privteMethods
		var createMomentDate = function( year, month, day, hour, min ){
			var utc = Date.UTC(year | 0, month | 0, day | 0, hour | 0, min | 0);
      		return moment(utc);
		};

		service.getHoliday = function(){
			if( zhxBaseCalendar.showHoliday() ){
				//TODO判断URL合法性
				$http.get( zhxBaseCalendar.getHolidayUrl() ).success(function(res){
					holidayDefer.resolve(res);
				})
				.error(function(){
					holidayDefer.reject();
				});

			}

			return holidayDefer.promise;
		};

		/**
		 * 获取今天日期对象
		 * @return {[Moment Object]} [description]
		 */
		service.getToday = function(){
			return moment();
		};

		service.getEvBetweenDays = function(){
			return [eventStartDate,eventEndDate];
		};

		/**
		 * 判断两个日期是否为相同
		 * @param  {[String]}  date1 
		 * @param  {[String]}  date2
		 * @return {Boolean}  
		 */
		service.isTheSameDay = function( date1, date2 ){
			return new Date(date1).getTime() === new Date(date2).getTime();
		};

		/**
		 * 判断某个moment日期是否在某个日期所在的月份内
		 * @param  {[type]}  mDate          [description]
		 * @param  {[type]}  checkMonthDate [description]
		 * @return {Boolean}                [description]
		 */
		service.isInMonth = function( mDate, checkMonthDate ){
			return mDate.month() === checkMonthDate.month();
		};

		/**
		 * 判断moment日期是否周末（周六周日）
		 * @param  {[type]}  mDate [description]
		 * @return {Boolean}       [description]
		 */
		service.isWeekend = function( mDate ){
			return mDate.day() === 6 || mDate.day() === 0;
		};

		/**
		 * 获取日历顶部日名称
		 * @param  {[ String ]} format [格式化日名称 dddd or dd ]
		 * @return {[ Array ]}        [一二三四五六日]
		 */
		service.weekName = function(){
			var weekNames = [];

			var isLocale = zhxBaseCalendar.isLocale() ? 1 : 0;

			for( var i = 0; i < 7; i++ ){
				//TODO 需要配置，非中文不需要+1
				weekNames.push( moment().day( i + isLocale ) );
			}
			return weekNames;
		};

		/**
		 * 获取一周内的moment日期
		 */
		service.getDaysInWeek = function(m){
			var days = [];
			var year = m.year(),
				month = m.month(),
				offset = m.utcOffset() / 60,
				day = m.date(),
				actualOffset;

			for( var i = 0; i < 7; i++ ){
				var pushedDate = createMomentDate( year, month, day, 0 - offset, 0, false );
					actualOffset = pushedDate.utcOffset() / 60;
				if( actualOffset !== offset ){
					pushedDate = createMomentDate( year, month, day, 0 - actualOffset, 0, false );
				}
				days.push(pushedDate);
				day++;
			}

			return days;
		}

		/**
		 * 根据传递的moment日期获取所在月内所有42个moment日期
		 * @return {[Array]} [传递一个moment对象]
		 * [
		 * 		[ days in 1st week ]
		 * 		[ days in 2nd week ]
		 * 		[ ... ]
		 * ]
		 * 6行7列[二维数组]
		 */
		service.getWeekDays = function(m){

			var m = moment(m) || moment(),
				firstDay =  moment().weekday(0).day(),
				startYear = m.year(),
				startMonth = m.month(),
				weeks = [];
			//先设置为1号
			m.date(1);
			//取当月1号为星期几
			var day = m.day();
	
			m.date( firstDay - (day + (firstDay >= day ? 6 : -1)) );
			//如果第一周（第一行）7天都为上个月补全，则第一行应直接跨过这些天
			if( moment(m).add(7,'days').date() === 1 ) m.add(7,'days');	
			//循环出所有42格日期
	        while (weeks.length < 6) {

	          weeks.push( service.getDaysInWeek(m) );

	          m.add(7, 'd');
	        }

	        return weeks;

		};

		/**
		 * 获取当前日历的实时日期
		 * @param  {[type]} date [description]
		 * @return {[type]}      [description]
		 */
		service.getCtrlDay = function(date){
			if( moment.isMoment(date) ) return date;
			if( moment.isDate(date) ) return moment(date);
			if( typeof(date) === 'string' && moment.isMoment( moment(date) ) ) return moment(date);
			return false;
		};

		/**
		 * 根据获取到的节日对象判断该日是否为节日
		 * @param  {[type]}  m [description]
		 * @return {Boolean}   [description]
		 */
		service.isHoliday = function(m,holiday){
			var i,j,t,holidayLen = holiday.length;
			for( i = 0; i < holidayLen; i++ ){
				var thisHoliday = holiday[i],
					hDays = thisHoliday.holidayDate, hDaysLen = hDays.length,
					tDays = thisHoliday.workDate, tDaysLen = tDays.length,
					hname = thisHoliday.name;
				for( j = 0; j < hDaysLen; j++ ){
					var hd = hDays[j];
					if( new Date(m).getTime() === new Date(hd).getTime() ) return { isHoliday : true, name : hname };
				}
				for( t = 0; t < tDaysLen; t++ ){
					var td = tDays[t];
					if( new Date(m).getTime() === new Date(td).getTime() ) return { isWorkDay : true, name : hname };
				}
			}
			return false;
		};

		/**
		 * 根据moment基础数据重构日历每一天的自定义数据对象
		 * 至少应该包括以下自定义字段：
		 * 
		 * mDate 			[moment object] 当前日期moment 
		 * isToday			[boolean]		是否今日
		 * isInMonth 		[boolean]		是否在当前月内，表示除当前月的其他日期都应为false,为样式处理做准备
		 * isWeekend		[boolean]		是否周末
		 * isHoliday		[boolean]		是否假日
		 * isWorkDay      	[boolean]		是否假日后的换班
		 * holidayType		[number]		什么假日[后期可进行扩展，例如中秋节，国庆节等]   **暂未使用**
		 *
		 * 内部使用的XY坐标系，表示每一个日期在42格中的位置
		 * __dayCoordX,__dayCoordY
		 *
		 * @return { Array } [可以直接进行渲染的42格数据对象]
		 */
		service.createCalDate = function(mDateArray,ctrlDate ){

			var weekDaysData = [],
			// coordX = 1,coordY = 1,
			i,j;

			for( i = 0; i < mDateArray.length; i++ ){
				var week = mDateArray[i],
					weekLen = week.length;
				var tmpArr = [];
				// coordX = 1;
				// coordY = i + 1;
				for( j = 0; j < weekLen; j++ ){
					var mDate = week[j],
						mfDate = mDate.format('YYYY-MM-DD');

					var daysObject = {
						// __dayCoordX 	: coordX,
						// __dayCoordY 	: coordY,
						__isToday 		: service.isTheSameDay( mfDate, service.getToday().format('YYYY-MM-DD') ),
						__isInMonth 	: service.isInMonth( mDate, ctrlDate ),
						// __isWeekend 	: service.isWeekend( mDate ),
						__isHoliday		: false,
						__isWorkDay		: false,
						__holidayName   : null,
						__mDate 		: mDate,
						__mfDate		: mfDate
					};
					if( i === 0 && j === 0 ) calStartDate = mDate;
					if( i === mDateArray.length - 1 && j === weekLen - 1 ) calEndDate = mDate;
					tmpArr.push( daysObject );
					// coordX++;
				}
				weekDaysData.push(tmpArr);
				// coordY++;
			}

			return weekDaysData;

		};

		/**
		 * 根据获取的节日信息，将此整合至日历中
		 * @param  {[Array]} calDate [ 日历基础42格数组]
		 * @param  {[Array]} holiday [ 节日信息数组 ]
		 * @return {[Array]}         [ 整合后的日历数组 ]
		 */
		service.createHolidayCal = function( calDate, holiday ){

			var i,j,t,z,calDateLen = calDate.length, holidayLen = holiday.length;
			
			for( i = 0; i < calDateLen; i++ ){
				var week = calDate[i],
					weekLen = week.length;
				for( j = 0; j < weekLen; j++){
					var day = week[j];
					var isTheDay = service.isHoliday(day.__mfDate, holiday);
					if( isTheDay ){
						if( isTheDay.isHoliday ) day.__isHoliday = true;
						if( isTheDay.isWorkDay ) day.__isWorkDay = true;
						day.__holidayName = isTheDay.name;
					}
				}
			}

			return calDate;

		};


		/**
		 * 渲染日历每日数据的自定义方法
		 * 日期拥有day {} 对象，这里直接为day 扩展一个 extendProps 对象来显示自定义内容
		 * @param  {[Array]}  calDate        [日历42格对象]
		 * @param  {[Object]} calendarEvents [日历的options选项]
		 * @return {[Array]}                 [更新后的日历42格对象]
		 */
		service.renderCalDataByOptions = function( calDate, calendarOpts ){

			var calendarEvents = angular.copy( calendarOpts.event );

			var eventDateKey = calendarEvents.eventDateKey || 'date';

			if( calDate && calendarEvents && angular.isArray(calDate) && angular.isArray(calendarEvents) ){
				var i,j,t,calDateLen = calDate.length,calendarEvtLen = calendarEvents.length,
					calRealStartDate = angular.copy( calStartDate ),
					calRealEndDate =  angular.copy( calEndDate );

				//循环所有自定义日历事件
				for( i = 0; i < calendarEvtLen; i++ ){
					var evData = calendarEvents[i],
						ctnLoop = true,
						__isInMonth = moment( evData[eventDateKey] ).isBetween(calRealStartDate.subtract(1,'d'),calRealEndDate.add(1,'d'));

					if( i === 0 ) eventStartDate = evData[eventDateKey];
					if( i === calendarEvtLen - 1 ) eventEndDate = evData[eventDateKey];
					//如果该事件的日期在当前显示的日历日期范围内则添加此事件至日历指定日期中	
					if( __isInMonth ){
						//循环日历周
						for( j = 0; j < calDateLen; j++ ){
							var week = calDate[j],
							weekLen = week.length;
							//如果上次循环中该事件已被添加，则终止本次日历循环
							if( !ctnLoop ) break;
							//循环日历天
							for( t = 0; t < weekLen; t++ ){
								var day = week[t],
									md = new Date( day.__mfDate ).getTime() === new Date( evData.date ).getTime();
								if( md ){
									var extendProps = {
										userExtendProp : evData	//用户自定义扩展的数据对象
									}
									//不需要深度拷贝merge
									angular.extend(day, extendProps);
									ctnLoop = !ctnLoop;
									break;
								}
							}
						}
					}
				}

				return calDate;
			}

		};

		/**
		 * 创建一个弹出层，共日历扩展使用（左右键点击等等）
		 * @param  {[type]} event      [widnow事件对象]
		 * @param  {[type]} dom        [一个HTML字符串，可以直接添加进弹出层中]
		 * @param  {[type]} compileScp [作用域，传递了该作用域后则会进行Angular编译]
		 * @param  {[type]} isolate    [是否为独立作用域，如果使用了独立作用域，则在移除弹出层时会自动销毁该作用域]
		 * @return {[type]}            [一个编译否的弹出层对象]
		 */
		service.createCalLayer = function(event, dom, compileScp, isolate ){

			var ev = event || window.event,
				x = ev.pageX,
				y = ev.pageY,
				dw = document.documentElement.clientWidth,
				dh = document.documentElement.clientHeight,
				layers = angular.element('.zhx-cal-layer');

			var isCreated = layers.length ? true : false;	

			var __createLayer = function(){

				var layer = angular.element('<div class="zhx-cal-layer" style="opacity:0"></div>');
				//将DOM模板放入LAYER中
				dom && layer.append(dom);
				//如果启用编译，则使用angular进行编译处理
				compileScp && $compile(layer)(compileScp);
				//声明一个移除LAYER方法
				var removeLayer = function(){
					layer.remove();
					isolate && compileScp.$destroy();
					angular.element('body').off('click',removeLayer);
				}
				//给BODY绑定一个移除LAYER的事件
				angular.element('body').on('click',removeLayer);
				//为LAYER设定具体弹出位置
				$timeout(function(){

					var layerHeight = layer[0].clientHeight,
						layerWidth = layer[0].clientWidth,
						offsetHeight = dh - layerHeight,
						offsetWidth = dw - layerWidth;

					//防止LAYER溢出屏幕	
					layer.css({ top : offsetHeight - y < 10 ? offsetHeight - 10 : y, left : offsetWidth - x < 10 ?  offsetWidth - 10 : x, "opacity" : 1 });

				});

				return layer;

			};

			isCreated && layers.remove();

			return __createLayer();
		};

		service.showLoading = function(isShown){
			isShowLoading = isShown;
		};

		service.getLoadingStatus = function(){
			return isShowLoading;
		};

		return service;

	}]);

	/**
	 * 日历模板的moment格式化过滤器
	 */
	CALENDAR.filter('mDateFormat', function () {
		return function (m, format) {
			if ( !(moment.isMoment(m) ) ) {
				return (m) ? moment(m).format(format) : '';
			}
			return m.format(format);
		};
	});

	/**
	 * 日历总控制器
	 */
	CALENDAR.controller('calendarBaseCrl',['$scope','$q','zhxBaseCalendar','zhxBaseCalUtils','$timeout',function($scope,$q,zhxBaseCalendar,zhxBaseCalUtils,$timeout){

		var $calendarCtrl = this;

		var getOptionsDefer = $q.defer();

		$scope.showLoadingMask = false;

		//获取日历顶部的日名称
		$scope.weekName = zhxBaseCalUtils.weekName();

		//日历实时日期，日历所有操作都会更新此日期
		if( angular.isUndefined( $scope.options ) ){
			$scope.ctrlDay = zhxBaseCalUtils.getToday();
		} else {
			$scope.ctrlDay = angular.isUndefined( $scope.options.firstRenderDate ) ? zhxBaseCalUtils.getToday() : zhxBaseCalUtils.getCtrlDay( $scope.options.firstRenderDate );
		}

		//表头显示当前日期
		$scope.headerDisplayDate = $scope.ctrlDay;

		// $scope.lastUpdateDate = angular.copy( $scope.ctrlDay );

		//获取指定日期所在月份所有42个日期对象
		$scope.weekDays = zhxBaseCalUtils.getWeekDays( $scope.ctrlDay );

		//最终整合过格式的日历需要的42格日期对象
		$scope.calendarDate = zhxBaseCalUtils.createCalDate( $scope.weekDays, $scope.ctrlDay );

		//判断是否启用了日历节日显示
		if( zhxBaseCalendar.showHoliday() ){
			zhxBaseCalUtils.getHoliday().then(function(res){
				$scope.calendarDate = zhxBaseCalUtils.createHolidayCal( $scope.calendarDate, res );
			});	
		}

		/**
		 * 获取OPTIONS包括数据加载完毕的PROMISE状态
		 * @return {[type]} [description]
		 */
		$calendarCtrl.getDataReady = function(){
			return getOptionsDefer.promise;
		};

		/**
		 * 获取OPTIONS选项
		 * @return {[type]} [description]
		 */
		$calendarCtrl.getOptions = function(){
			return !angular.isUndefined( $scope.options ) && $scope.options;
		};

		/**
		 * 翻页日历按钮使用
		 * @param  {[nubmer]} number [ 正数或复数或0，表示要增加或减少的月份或年份等]
		 * @param  {[string]} type   [ moment的格式化字符 M表示月]
		 */
		$calendarCtrl.changeCalDate = function( number, type ){

			//切换日历不为『今日』
			if( number !== 0 ) {
				$scope.ctrlDay.add(number,type);
			} else {
				//如果日历此时就在本月，再次点击今日按钮将不做任何操作
				var cd = $scope.ctrlDay.format('YYYY-MM'),
					nd = moment().format('YYYY-MM');
				if( cd === nd ) return; 
		
				$scope.headerDisplayDate = $scope.ctrlDay = zhxBaseCalUtils.getToday();
				// $scope.lastUpdateDate = angular.copy( $scope.ctrlDay );

			}
			$scope.weekDays = zhxBaseCalUtils.getWeekDays( $scope.ctrlDay );
			$scope.calendarDate = zhxBaseCalUtils.createCalDate( $scope.weekDays, $scope.ctrlDay );
			//判断是否启用了日历节日显示
			if( zhxBaseCalendar.showHoliday() ){
				zhxBaseCalUtils.getHoliday().then(function(res){
					$scope.calendarDate = zhxBaseCalUtils.createHolidayCal( $scope.calendarDate, res );
				});	
			}
			var opts = $scope.options;
			//渲染自定义日历数据
			if( !angular.isUndefined(opts) ){
				//如果自定义日历了日历并且设置了onChange事件来更新日历，则使用onChange来更新日历数据
				if( !angular.isUndefined(opts.event) && !angular.isUndefined(opts.onChange) && angular.isFunction(opts.onChange) ){
					//如果用户设置了自动更新，则系统会检测加载进来事件的起止日期，超过起止日期自动执行onChange方法
					if( angular.isUndefined(opts.updateAutomic) || opts.updateAutomic ){
						//如果日期变动在设置间隔范围内，则不需要请求新数据
						var eventBetweenDays = zhxBaseCalUtils.getEvBetweenDays(),
							eventStartDate = moment(eventBetweenDays[0]).subtract(1,'d'),
							eventEndDate = moment(eventBetweenDays[1]).add(1,'d');
						var diffsDay = $scope.ctrlDay.isBetween( eventStartDate, eventEndDate );
						if( diffsDay ){
							$timeout(function(){
								$scope.calendarDate = zhxBaseCalUtils.renderCalDataByOptions( $scope.calendarDate, opts  );
							})
						//变动范围外才需要请求新数据
						} else {
							zhxBaseCalUtils.showLoading(true);
							opts.onChange.call( $calendarCtrl, angular.copy( $scope.ctrlDay ) );
						}
					//如果设置为false则每次翻页都会读取新数据
					} else {
						zhxBaseCalUtils.showLoading(true);
						opts.onChange.call( $calendarCtrl, angular.copy( $scope.ctrlDay ) );
					}
				//如果options中未定义onChange事件，则继续根据首次获取的event来渲染日历自定义事件	
				} else {
					$scope.calendarDate = zhxBaseCalUtils.renderCalDataByOptions( $scope.calendarDate, opts  );
				}
			}
		};

		/**
		 * 添加一个options event 变化监控
		 * 该监控的目的是为了检测用户是否定义或修改了CALENDAR的options
		 */
		if( $scope.options ){
			var setLoading,loadingDelay = 300;
			$scope.$watch('options.event',function(nv, ov){
				//首次加载数据event为空时显示LOADING
				if( angular.isUndefined(ov) || ( angular.isArray(ov) && !ov.length ) || ov === null || ov === '' ){
					//设置一个loading，日历初始化后300毫秒显示
					if( angular.isUndefined(setLoading) ){
						setLoading = $timeout(function(){
							zhxBaseCalUtils.showLoading(true);
						},loadingDelay);
					}
				}
				if( !angular.isUndefined(nv) && nv !== ov ){
					//如果读取速度快于300毫秒，则不显示loading
					if( setLoading ) $timeout.cancel( setLoading );
					//获取到opt后更新promise状态
					getOptionsDefer.resolve( $scope.options );
					//更新数据
					$timeout(function(){
						$scope.calendarDate = zhxBaseCalUtils.renderCalDataByOptions( $scope.calendarDate, $scope.options  );
					});
					//每次更新数据都保存一个更新日期
					// $scope.lastUpdateDate = angular.copy( $scope.ctrlDay );
					zhxBaseCalUtils.showLoading(false);
				}
			});	

			/**
			 * Loading的一个简单watch
			 */
			$scope.$watch(function(){
				return zhxBaseCalUtils.getLoadingStatus();
			},function(nv,ov){
				$scope.showLoadingMask = nv ? true : false;
			});

		}

	}]);

	/**
	 * 日历基础指令，该指令仅为日历相关逻辑与展示，不包含任何业务逻辑处理。	
	 *
	 * 基础日历组件包含以下功能：
	 *
	 * - 月历展示
	 * - 当前日期展示
	 * - 日期翻页，上一月，今天，下一月
	 * - 展示今天
	 *
	 * 日历中每一天都为一个自定义的日期对象，其中包含的字段请查阅：
	 * service.createCalDate()
	 * 方法中定义的
	 * 后期会扩展接口，以便在其中定义业务罗技处理的数据字段
	 * 
	 */
	CALENDAR.directive('zhxBaseCalendar',['zhxBaseCalUtils',function(zhxBaseCalUtils){
		return {
			restrict : 'AE',
			scope : {
				options : '='
			},
			replace : true,
			controller : "calendarBaseCrl",
			link : function( scope, tElement, tAttrs, calendar ){

				//上一月
				scope.prevMonth = function(){
					calendar.changeCalDate(-1,'M');
				};
	
				//今天
				scope.toDay = function( ctrlDay ){
					calendar.changeCalDate(0);
				};

				//下一月				
				scope.nextMonth = function( ctrlDay ){
					calendar.changeCalDate(1,'M');
				};

			},
			templateUrl : 'zhxCalendar.tpl.vicco'
		}
	}]);

	/**
	 * 日期单独格子指令，与模板进行相互绑定，并进行自定配置项的渲染与事件绑定
	 * 
	 */
	CALENDAR.directive('zhxCalDay', ['$compile','$timeout','$controller',function($compile,$timeout,$controller){
		return {
			restrict : 'AE',
			require : '^?zhxBaseCalendar',
			compile : function(){
				return {
					post: function postLink( scope, tElement, tAttrs, cal ){
						//获取CAL的OPTIONS是否加载完毕
						var optionsPromise = cal.getDataReady();
						optionsPromise.then(function( options ){
							//为日历绑定自定义控制器
							var waitUserProps = scope.$watch('day.userExtendProp',function(nv,ov){
								if( nv && nv !== ov ){
									if( !options.renderController || !scope.day.userExtendProp ) return;
									$controller( options.renderController, { $scope : scope, $element : tElement, $options : options } );
									//绑定完毕立即清除watch
									waitUserProps();
								}
							});
						})
					}
				}
			} 
		}
							
	}]);

	CALENDAR.directive('ngRightClick', ['$parse',function($parse) {
	    return function(scope, element, attrs) {
	        var fn = $parse(attrs.ngRightClick);
	        element.bind('contextmenu', function(event) {
	            scope.$apply(function() {
            	 	var ev = event || window.event;
	                ev.preventDefault();
	                fn(scope, {$event:ev});
	            });
	        });
	    };
	}]);

	/**
	 * 配置日历基础模板
	 */
	CALENDAR.run(['$templateCache',function($templateCache){

		/**
		 * 日历基础模板，无需自定义修改
		 * @type {String}
		 */
		$templateCache.put('zhxCalendar.tpl.vicco',
			'<div class="zhx-cal-wrapper">' +
				'<div class="zhx-cal-header">' +
					'<div class="zhx-cal-header-date" ng-bind="headerDisplayDate | mDateFormat:\'YYYY年MM月\' "></div>' +
					'<div class="zhx-cal-header-ctrl">'+
						'<div class="zhx-cal-ctrl-prev iconfont icon-left" ng-click="prevMonth();"></div>' +
						'<div class="zhx-cal-ctrl-today" ng-click="toDay();">今日</div>' +
						'<div class="zhx-cal-ctrl-next iconfont icon-right" ng-click="nextMonth();"></div>' +
					'</div>' +
				'</div>' +
				'<div class="zhx-cal-day-name">' +
					'<ul>' +
						'<li ng-repeat=" name in ::weekName" ng-bind="::name | mDateFormat:\'ddd\' "></li>' +
					'</ul>' +
				'</div>' +
				'<div class="zhx-cal-body">' +
					'<ul ng-repeat="week in calendarDate track by $index " ng-class="::{ lastWeek : $last } " >' +
						'<li ng-repeat="day in week track by $index " ng-class="::{ lastDayInWeek : $last } " >' +
							'<div ng-class="{ outOfMonth : !day.__isInMonth }">' +
								'<span class="day-number" ng-class="{ isToday : day.__isToday }">' + 
									'<span class="day-holiday" ng-if="day.__isHoliday" ng-bind="day.__holidayName"></span>' +
									'<span class="day-workday" ng-if="day.__isWorkDay">补班</span>' +
									'<span>{{ day.__mDate | mDateFormat:day.__mDate.date() === 1 && !day.__isToday && !day.__isHoliday ? \'M月D日\' : \'D\' }}</span>' +
								'</span>' +
								'<zhx-cal-day style="width:100%;"></zhx-cal-day>' +
							'</div>' +
						'</li>' +
					'</ul>' +
				'</div>' +
				'<div class="zhx-cal-mask" ng-if="showLoadingMask">' +
					'<div class="spinner">' + 
					  '<div class="dot1"></div>' + 
					  '<div class="dot2"></div>' + 
					'</div>' + 
				'</div>' +
			'</div>');
	}]);

})()